package com.lp.easymethodlink.service;

import com.lp.easymethodlink.model.CallHierarchyNode;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Markdown导出服务
 */
public class MarkdownExportService {
    
    /**
     * 将调用链路导出为Markdown格式
     * @param rootNode 根节点
     * @return Markdown文本
     */
    public String exportToMarkdown(CallHierarchyNode rootNode) {
        StringBuilder markdown = new StringBuilder();
        
        // 添加标题 - 极简风格
        markdown.append("# ").append(rootNode.getClassName())
                .append("类的").append(rootNode.getMethodName())
                .append("方法调用链路分析\n\n");
        
        // 添加生成时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        markdown.append("> 生成时间: ").append(sdf.format(new Date())).append("\n\n");
        
        // 添加目标方法信息 - 简洁格式
        markdown.append("## 目标方法\n\n");
        markdown.append("**类名:** `").append(rootNode.getClassName()).append("`\n");
        markdown.append("**方法名:** `").append(rootNode.getMethodName()).append("`\n");
        
        if (rootNode.getMethodDescription() != null && !rootNode.getMethodDescription().isEmpty()) {
            markdown.append("**描述:** ").append(rootNode.getMethodDescription()).append("\n");
        }
        
        if (rootNode.isControllerMethod()) {
            markdown.append("**请求方式:** `").append(rootNode.getHttpMethod()).append("`\n");
            markdown.append("**API路径:** `").append(rootNode.getApiPath()).append("`\n");
        }
        
        markdown.append("\n");
        
        // 添加调用链路 - 简洁标题
        markdown.append("## 调用链路\n\n");
        
        if (rootNode.getChildren().isEmpty()) {
            markdown.append("> 未找到调用者\n\n");
        } else {
            // 直接显示调用者
            buildMarkdownTreeWithTarget(markdown, rootNode, 0);
        }
        
        // 添加统计信息 - 简洁表格
        markdown.append("\n## 统计信息\n\n");
        int totalCallers = countTotalCallers(rootNode);
        int maxDepth = calculateMaxDepth(rootNode, 0);
        int controllerInterfaces = countControllerInterfaces(rootNode);
        
        markdown.append("- 总调用者数量: **").append(totalCallers).append("**\n");
        markdown.append("- 最大调用深度: **").append(maxDepth).append("**\n");
        markdown.append("- Controller接口数量: **").append(controllerInterfaces).append("**\n\n");
        
        // 添加水印信息
        markdown.append("\n---\n\n");
        markdown.append("*本文档由 EasyMethodLink 插件自动生成*\n");
        
        return markdown.toString();
    }
    
    /**
     * 构建包含目标方法的Markdown树形结构
     * @param markdown StringBuilder
     * @param rootNode 根节点（目标方法）
     * @param depth 深度
     */
    private void buildMarkdownTreeWithTarget(StringBuilder markdown, CallHierarchyNode rootNode, int depth) {
        // 只显示调用者，不显示目标方法
        if (!rootNode.getChildren().isEmpty()) {
            // 构建反向的调用链，Controller在顶层
            buildReversedCallChain(markdown, rootNode);
        }
    }
    
    /**
     * 构建调用者的Markdown树形结构
     * @param markdown StringBuilder
     * @param node 节点
     * @param depth 深度
     */
    private void buildMarkdownTreeForCaller(StringBuilder markdown, CallHierarchyNode node, int depth) {
        // 添加缩进
        for (int i = 0; i < depth; i++) {
            markdown.append("  ");
        }
        markdown.append("- ");
        
        // 添加调用者信息 - 只显示类名和方法名，不显示路径
        markdown.append("🔗 **").append(node.getClassName()).append(".").append(node.getMethodName()).append("**");
        
        markdown.append("\n");
        
        // 添加结构化的方法信息
        if (node.isControllerMethod()) {
            // Controller方法显示请求方式、API路径和方法描述
            for (int i = 0; i < depth + 1; i++) {
                markdown.append("  ");
            }
            markdown.append("**请求方式**: `").append(node.getHttpMethod()).append("`\n");
            
            for (int i = 0; i < depth + 1; i++) {
                markdown.append("  ");
            }
            markdown.append("**API路径**: `").append(node.getApiPath()).append("`\n");
            
            for (int i = 0; i < depth + 1; i++) {
                markdown.append("  ");
            }
            if (node.getMethodDescription() != null && !node.getMethodDescription().isEmpty()) {
                markdown.append("**方法描述**: ").append(node.getMethodDescription()).append("\n");
            } else {
                markdown.append("**方法描述**: Controller方法，处理HTTP请求\n");
            }
        } else {
            // 非Controller方法只显示方法描述
            for (int i = 0; i < depth + 1; i++) {
                markdown.append("  ");
            }
            if (node.getMethodDescription() != null && !node.getMethodDescription().isEmpty()) {
                markdown.append("**方法描述**: ").append(node.getMethodDescription()).append("\n");
            } else {
                // 根据类型添加默认描述
                if (node.getClassName() != null && node.getClassName().toLowerCase().contains("service")) {
                    markdown.append("**方法描述**: 服务层方法\n");
                } else if (node.getClassName() != null && node.getClassName().toLowerCase().contains("controller")) {
                    markdown.append("**方法描述**: 控制器方法\n");
                } else {
                    markdown.append("**方法描述**: 业务方法\n");
                }
            }
        }
        
        // 递归处理子节点
        for (CallHierarchyNode child : node.getChildren()) {
            buildMarkdownTreeForCaller(markdown, child, depth + 1);
        }
    }
    
    /**
     * 构建反向调用链，Controller在顶层
     * @param markdown StringBuilder
     * @param rootNode 根节点
     */
    private void buildReversedCallChain(StringBuilder markdown, CallHierarchyNode rootNode) {
        // 收集所有Controller节点及其调用链路
        java.util.Map<CallHierarchyNode, java.util.List<CallHierarchyNode>> controllerToServices = new java.util.LinkedHashMap<>();
        findControllerServicePairs(rootNode, controllerToServices);
        
        // 显示每个Controller及其调用的Service链路
        int controllerIndex = 1;
        for (java.util.Map.Entry<CallHierarchyNode, java.util.List<CallHierarchyNode>> entry : controllerToServices.entrySet()) {
            CallHierarchyNode controller = entry.getKey();
            java.util.List<CallHierarchyNode> servicePath = entry.getValue();
            
            // 显示Controller（使用有序列表）
            displayControllerNode(markdown, controller, 0, controllerIndex);
            
            // 反转路径顺序，使其从近到远显示（Controller -> Service1 -> Service2 -> ...）
            java.util.List<CallHierarchyNode> reversedPath = new java.util.ArrayList<>(servicePath);
            java.util.Collections.reverse(reversedPath);
            
            // 显示调用路径中的Service节点（相对于Controller缩进）
            for (int i = 0; i < reversedPath.size(); i++) {
                CallHierarchyNode serviceNode = reversedPath.get(i);
                // 第一个Service深度为1，后续递增
                int serviceDepth = 1 + i;
                displayServiceNode(markdown, serviceNode, serviceDepth);
            }
            
            controllerIndex++;
        }
    }
    
    /**
     * 找到Controller和Service的对应关系
     * @param rootNode 根节点
     * @param controllerToServices Controller到Service的映射
     */
    private void findControllerServicePairs(CallHierarchyNode rootNode, java.util.Map<CallHierarchyNode, java.util.List<CallHierarchyNode>> controllerToServices) {
        // 从根节点开始，递归查找每个Controller及其到目标方法的调用路径
        findControllersRecursive(rootNode, new java.util.ArrayList<>(), controllerToServices);
    }
    
    /**
     * 递归查找Controller节点及其调用路径
     * @param currentNode 当前节点
     * @param currentPath 当前路径（从目标方法开始）
     * @param controllerToServices Controller到Service的映射
     */
    private void findControllersRecursive(CallHierarchyNode currentNode, java.util.List<CallHierarchyNode> currentPath, java.util.Map<CallHierarchyNode, java.util.List<CallHierarchyNode>> controllerToServices) {
        java.util.List<CallHierarchyNode> newPath = new java.util.ArrayList<>(currentPath);
        newPath.add(currentNode);
        
        if (currentNode.isControllerMethod()) {
            // 找到Controller，保存路径（去掉Controller本身，只保存Service路径）
            java.util.List<CallHierarchyNode> servicePath = new java.util.ArrayList<>(newPath);
            servicePath.remove(servicePath.size() - 1); // 移除Controller节点
            controllerToServices.put(currentNode, servicePath);
        }
        
        // 继续向上查找
        for (CallHierarchyNode child : currentNode.getChildren()) {
            findControllersRecursive(child, newPath, controllerToServices);
        }
    }
    
    /**
     * 显示Controller节点
     * @param markdown StringBuilder
     * @param controller Controller节点
     * @param depth 深度
     * @param controllerIndex Controller索引（用于有序列表）
     */
    private void displayControllerNode(StringBuilder markdown, CallHierarchyNode controller, int depth, int controllerIndex) {
        for (int i = 0; i < depth; i++) {
            markdown.append("  ");
        }
        markdown.append(controllerIndex).append(". 🔗 **").append(controller.getClassName()).append(".").append(controller.getMethodName()).append("**\n");
        
        for (int i = 0; i < depth + 1; i++) {
            markdown.append("  ");
        }
        markdown.append("   - 请求方式: `").append(controller.getHttpMethod()).append("`\n");
        
        for (int i = 0; i < depth + 1; i++) {
            markdown.append("  ");
        }
        markdown.append("   - API路径: `").append(controller.getApiPath()).append("`\n");
        
        if (controller.getMethodDescription() != null && !controller.getMethodDescription().isEmpty()) {
            for (int i = 0; i < depth + 1; i++) {
                markdown.append("  ");
            }
            markdown.append("   - 描述: ").append(controller.getMethodDescription()).append("\n");
        }
    }
    
    /**
     * 显示Service节点
     * @param markdown StringBuilder
     * @param serviceNode Service节点
     * @param depth 深度
     */
    private void displayServiceNode(StringBuilder markdown, CallHierarchyNode serviceNode, int depth) {
        // 确保Service节点有正确的缩进（至少2个空格为一个缩进级别）
        for (int i = 0; i < depth; i++) {
            markdown.append("  ");
        }
        markdown.append("   - **").append(serviceNode.getClassName()).append(".").append(serviceNode.getMethodName()).append("**\n");
        
        if (serviceNode.getMethodDescription() != null && !serviceNode.getMethodDescription().isEmpty()) {
            for (int i = 0; i < depth + 1; i++) {
                markdown.append("  ");
            }
            markdown.append("     > 方法描述：").append(serviceNode.getMethodDescription()).append("\n");
        }
    }
    
    /**
     * 计算总调用者数量
     * @param node 节点
     * @return 总数量
     */
    private int countTotalCallers(CallHierarchyNode node) {
        int count = node.getChildren().size();
        for (CallHierarchyNode child : node.getChildren()) {
            count += countTotalCallers(child);
        }
        return count;
    }
    
    /**
     * 计算最大调用深度
     * @param node 节点
     * @param currentDepth 当前深度
     * @return 最大深度
     */
    private int calculateMaxDepth(CallHierarchyNode node, int currentDepth) {
        if (node.getChildren().isEmpty()) {
            return currentDepth;
        }
        
        int maxDepth = currentDepth;
        for (CallHierarchyNode child : node.getChildren()) {
            int childDepth = calculateMaxDepth(child, currentDepth + 1);
            maxDepth = Math.max(maxDepth, childDepth);
        }
        
        return maxDepth;
    }
    
    /**
     * 计算Controller接口数量
     * @param node 节点
     * @return Controller接口数量
     */
    private int countControllerInterfaces(CallHierarchyNode node) {
        int count = 0;
        
        // 检查当前节点是否为Controller方法
        if (node.isControllerMethod()) {
            count = 1;
        }
        
        // 递归检查子节点
        for (CallHierarchyNode child : node.getChildren()) {
            count += countControllerInterfaces(child);
        }
        
        return count;
    }
    
    /**
     * 保存Markdown到文件
     * @param markdown Markdown内容
     * @param file 目标文件
     * @throws IOException IO异常
     */
    public void saveToFile(String markdown, File file) throws IOException {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
            writer.write(markdown);
        }
    }
}
